package com.pactera.asmp.server.common.bug.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import com.pactera.asmp.server.entity.TestReportJiraDTO;
import com.pactera.asmp.server.entity.TestReportJiraEntity;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.google.common.collect.Lists;
import com.pactera.asmp.server.entity.ProjectProductionConfig;
import com.pactera.asmp.server.pojo.TestReport;
import com.pactera.asmp.server.utils.HttpResult;

@Service
public class ZentaoHandlerImpl extends AbstractBugHandler {

    private static final Logger logger = LoggerFactory.getLogger(ZentaoHandlerImpl.class);

    private static final String LOGIN_URL = "user-login.html";

    private static final String ADDBUG_URL = "bug-create-%s-0-moduleID=0.html";

    private static final String PRODUCT_URL = "product-index-no.json";

    private static final String PROJECT_URL = "project-index-no.json";

    private static final String BUGLIST_URL = "bug-browse-%s-0-unclosed.json";

    private static final String BUGDETAIL_URL = "bug-view-%s.json";

    private static final String BUGDETAIL_HTML_URL = "bug-view-%s.html";

    private static final String BUGPAGE_URL = "bug-browse-%s-0-unclosed-0--%s-%s-%s.json";

    @Value("${minio.url}")
    private String fileUrl;

    @Value("${minio.bucketName}")
    private String buckName;

    /**
     * 上传bug信息到禅道
     * 
     * @param title
     * @param stepContent
     * @param testReport
     * @param projectProductionConfig
     * 
     * @return
     */
    @Override
    public String[] handleBug(String title, String stepContent, TestReport testReport,
            ProjectProductionConfig projectProductionConfig) {
        if(null == httpService.getHttpClient()) {
            try {
                zentaoLogin(projectProductionConfig);
            }catch(Exception ex) {
                return null;
            }
        }

        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        builder.setCharset(Charset.forName("utf-8"));
        ContentType contentType = ContentType.create("multipart/form-data",Charset.forName("UTF-8"));
        builder.addTextBody("product", projectProductionConfig.getBugProductId(), contentType);
        builder.addTextBody("module", "0", contentType);
        builder.addTextBody("project", projectProductionConfig.getBugProjectId(), contentType);
        builder.addTextBody("openedBuild[]", "trunk", contentType);
        builder.addTextBody("assignedTo", "", contentType);
        builder.addTextBody("deadline", "", contentType);
        builder.addTextBody("type", "automation", contentType);
        builder.addTextBody("os", "all", contentType);
        builder.addTextBody("browser", "all", contentType);
        builder.addTextBody("deadline", "", contentType);
        builder.addTextBody("title", title, contentType);
        builder.addTextBody("color", "", contentType);
        builder.addTextBody("severity", projectProductionConfig.getPriority(), contentType);
        builder.addTextBody("pri", projectProductionConfig.getPriority(), contentType);
        builder.addTextBody("steps", "<p>[步骤]</p>" + stepContent +"<p>[结果]</p> " + testReport.getContent() + "<p>[期望]</p>正常执行", contentType);
        builder.addTextBody("story", "", contentType);
        builder.addTextBody("task", "", contentType);
        builder.addTextBody("oldTaskID", "0", contentType);
        builder.addTextBody("mailto[]", "", contentType);
        builder.addTextBody("keywords", "", contentType);
        File logFile = null;
        File videoFile = null;
        if(StringUtils.isNotEmpty(testReport.getLogFileIndex())) {
            String logPath = fileUrl + "/" + buckName + "/" + testReport.getLogFileIndex();
            builder.addTextBody("labels[]", testReport.getLogFileIndex(), contentType);
            try {
                URL logUrl = new URL(logPath);
                logFile = File.createTempFile("temp", ".txt");

                InputStream inputStream= logUrl.openStream();
                OutputStream outputStream = new FileOutputStream(logFile);
                byte[] buffer =new byte[1024];
                int length;
                while((length = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, length);
                }
                inputStream.close();
                outputStream.close();
                builder.addBinaryBody("files[]", logFile);
            } catch (Exception ex) {
                logger.error("handleBug error. {}, {}", ex.getMessage());
            }
        }
        if(StringUtils.isNotEmpty(testReport.getVideoFileIndex())) {
            String videoPath = fileUrl + "/" + buckName + "/" + testReport.getVideoFileIndex();
            builder.addTextBody("labels[]", testReport.getVideoFileIndex(), contentType);
            try {
                URL videoUrl = new URL(videoPath);
                videoFile = File.createTempFile("tempVideo", videoPath.substring(videoPath.lastIndexOf(".")));

                InputStream inputStream= videoUrl.openStream();
                OutputStream outputStream = new FileOutputStream(videoFile);
                byte[] buffer =new byte[1024];
                int length;
                while((length = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, length);
                }
                inputStream.close();
                outputStream.close();
                builder.addBinaryBody("files[]", videoFile);
            } catch (Exception ex) {
                logger.error("handleBug error. {}, {}", ex.getMessage());
            }
        }
        if(StringUtils.isEmpty(testReport.getLogFileIndex()) && StringUtils.isEmpty(testReport.getVideoFileIndex())) {
            builder.addTextBody("labels[]", "", contentType);
            builder.addTextBody("files[]", "", contentType);
        }
        builder.addTextBody("uid", projectProductionConfig.getBugCreateUserId(), contentType);
        builder.addTextBody("case", "0", contentType);
        builder.addTextBody("caseVersion", "0", contentType);
        builder.addTextBody("result", "0", contentType);
        builder.addTextBody("testtask", "0", contentType);
        HttpEntity multipart = builder.build();

        try {
            String addUrl;
            if(projectProductionConfig.getBugUrl().endsWith("/")) {
                addUrl = projectProductionConfig.getBugUrl() + String.format(ADDBUG_URL, projectProductionConfig.getBugProductId());
            }else {
                addUrl = projectProductionConfig.getBugUrl() + "/" + String.format(ADDBUG_URL, projectProductionConfig.getBugProductId());
            }

            HttpResult httpResult = httpService.doPost(addUrl, multipart, null);
            // 解析响应
            if (null == httpResult || httpResult.getCode().intValue() != 200) {
                logger.error("handleBug error.HttpStatusCode:{}", httpResult.getCode());
            }else {
                return this.zentaoBugNo(projectProductionConfig, title, testReport);
            }
        } catch (IOException ex) {
            logger.error("handleBug error. {}, {}", ex.getMessage());
        } finally {
            // 关闭连接
            if(null != logFile) {
                logFile.delete();
            }
            if(null != videoFile) {
                videoFile.delete();
            }
        }
        return null;

    }

    @Override
    public String[] handleBugForMonkey(String title, String stepContent, TestReportJiraEntity testReportJiraEntity, TestReportJiraDTO testReportJiraDTO, ProjectProductionConfig projectProductionConfig) {
        return new String[0];
    }

    /**
     * 禅道获取项目列表
     * 
     * @param projectProductionConfig
     * 
     * @return
     */
    @Override
    public Map<String, String> getProjectList(ProjectProductionConfig projectProductionConfig) {
        if(null == httpService.getHttpClient()) {
            try {
                zentaoLogin(projectProductionConfig);
            }catch(Exception ex) {
                return null;
            }
        }
        try {
            String projectUrl;
            if(projectProductionConfig.getBugUrl().endsWith("/")) {
                projectUrl = projectProductionConfig.getBugUrl() + PROJECT_URL;
            }else {
                projectUrl = projectProductionConfig.getBugUrl() + "/" + PROJECT_URL;
            }

            HttpResult httpResult = httpService.doGet(projectUrl, null);
            // 解析响应
            if (null == httpResult || httpResult.getCode().intValue() != 200) {
                logger.error("getProjectList error.HttpStatusCode:{}", httpResult.getCode());
            }else {
                JSONObject object = JSONObject.parseObject(httpResult.getBody());
                JSONObject data = JSONObject.parseObject(object.get("data").toString());
                return JSONObject.parseObject(data.get("projects").toString(), new TypeReference<Map<String, String>> () {});
            }
        } catch (Exception ex) {
            logger.error("getProjectList error. {}, {}", ex.getMessage());
        }
        return new HashMap<>();
    }

    /**
     * 获取产品列表
     * 
     * @param projectProductionConfig
     * 
     * @return
     */
    @Override
    public Map<String, String> getProductionList(ProjectProductionConfig projectProductionConfig) {
        if(null == httpService.getHttpClient()) {
            try {
                zentaoLogin(projectProductionConfig);
            }catch(Exception ex) {
                return null;
            }
        }
        try {
            String productionUrl;
            if(projectProductionConfig.getBugUrl().endsWith("/")) {
                productionUrl = projectProductionConfig.getBugUrl() + PRODUCT_URL;
            }else {
                productionUrl = projectProductionConfig.getBugUrl() + "/" + PRODUCT_URL;
            }

            HttpResult httpResult = httpService.doGet(productionUrl, null);
            // 解析响应
            if (null == httpResult || httpResult.getCode().intValue() != 200) {
                logger.error("getProductionList error.HttpStatusCode:{}", httpResult.getCode());
            }else {
                JSONObject object = JSONObject.parseObject(httpResult.getBody());
                JSONObject data = JSONObject.parseObject(object.get("data").toString());
                return JSONObject.parseObject(data.get("products").toString(), new TypeReference<Map<String, String>> () {});
            }
        } catch (Exception ex) {
            logger.error("getProductionList error. {}, {}", ex.getMessage());
        }
        return new HashMap<>();
    }

    /**
     * 禅道login
     * 
     * @param httpClient
     * @param projectProductionConfig
     * @throws Exception 
     */
    private void zentaoLogin(ProjectProductionConfig projectProductionConfig) throws Exception {
        httpService.setHttpClient(HttpClients.createDefault());

        String loginUrl = null;
        if(projectProductionConfig.getBugUrl().endsWith("/")) {
            loginUrl = projectProductionConfig.getBugUrl() + LOGIN_URL;
        }else {
            loginUrl = projectProductionConfig.getBugUrl() + "/" + LOGIN_URL;
        }
        URL url = new URL(projectProductionConfig.getBugUrl());

        ArrayList<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("account", projectProductionConfig.getBugAccount()));
        params.add(new BasicNameValuePair("password", projectProductionConfig.getBugPassword()));
        params.add(new BasicNameValuePair("passwordStrength", "1"));
        params.add(new BasicNameValuePair("referer", url.getRef()));
        params.add(new BasicNameValuePair("verifyRand", "verify"));
        params.add(new BasicNameValuePair("keepLogin", "0"));
        UrlEncodedFormEntity entity1 = new UrlEncodedFormEntity(params, "utf8");

        HttpResult httpResult = httpService.doPost(loginUrl, entity1, null);
        // 解析响应
        if (null == httpResult || httpResult.getCode().intValue() != 200) {
            logger.error("zentaoLogin error.HttpStatusCode:{}", httpResult.getCode());
            if(null != httpResult) {
                logger.error("{}", httpResult.getBody());
            }
            throw new Exception("zentao login error");
        }
    }

    /**
     * 获取bug号
     * 
     * @param projectProductionConfig
     * @param title
     * @param testReport
     * 
     * @return
     */
    private String[] zentaoBugNo(ProjectProductionConfig projectProductionConfig,
            String title, TestReport testReport) {
        if(null == httpService.getHttpClient()) {
            try {
                zentaoLogin(projectProductionConfig);
            }catch(Exception ex) {
                return null;
            }
        }

        try {
            String bugUrl;
            if(projectProductionConfig.getBugUrl().endsWith("/")) {
                bugUrl = projectProductionConfig.getBugUrl() + String.format(BUGLIST_URL, projectProductionConfig.getBugProductId());
            }else {
                bugUrl = projectProductionConfig.getBugUrl() + "/" + String.format(BUGLIST_URL, projectProductionConfig.getBugProductId());
            }
            HttpResult httpResult = httpService.doGet(bugUrl, null);
            // 解析响应
            if (null == httpResult || httpResult.getCode().intValue() != 200) {
                logger.error("zentaoBugNo error.HttpStatusCode:{}", httpResult.getCode());
            }else {
                JSONObject object = JSONObject.parseObject(httpResult.getBody());
                Map<String, Object> dataMap = JSONObject.parseObject(object.get("data").toString(), new TypeReference<Map<String, Object>> () {});
                List<Map<String, String>> bugList = JSONObject.parseObject(JSONObject.toJSONString(dataMap.get("bugs")), new TypeReference<List<Map<String, String>>> () {});
                List<Map<String, String>> list = bugList.stream().filter(bug -> StringUtils.equals(StringEscapeUtils.unescapeHtml4(bug.get("title")), title)).collect(Collectors.toList());
                String url = projectProductionConfig.getBugUrl();
                if(!projectProductionConfig.getBugUrl().endsWith("/")) {
                    url += "/";
                }
                if(CollectionUtils.isNotEmpty(list)) {
                    String[] result = searchBug(url, list, testReport);
                    if(null != result && result.length > 0) {
                        return result;
                    }
                }
                // 获取下一页数据
                Map<String, Object> pager =(Map<String, Object>)dataMap.get("pager");
                if(Integer.parseInt(pager.get("pageTotal").toString()) < 2) {
                    return null;
                }
                for(int i=2; i<=Integer.parseInt(pager.get("pageTotal").toString()); i++) {
                    HttpResult httpResult1 = httpService.doGet(url + String.format(BUGPAGE_URL, projectProductionConfig.getBugProductId(),
                            pager.get("recTotal").toString(), pager.get("recPerPage").toString(), String.valueOf(i)), null);

                    if (null == httpResult1 || httpResult1.getCode().intValue() != 200) {
                        logger.error("zentaoBugNo error.HttpStatusCode:{}", httpResult1.getCode());
                        continue;
                    }
                    object = JSONObject.parseObject(httpResult1.getBody());
                    dataMap = JSONObject.parseObject(object.get("data").toString(), new TypeReference<Map<String, Object>> () {});
                    bugList = JSONObject.parseObject(JSONObject.toJSONString(dataMap.get("bugs")), new TypeReference<List<Map<String, String>>> () {});
                    list = bugList.stream().filter(bug -> StringUtils.equals(StringEscapeUtils.unescapeHtml4(bug.get("title")), title)).collect(Collectors.toList());
                    if(CollectionUtils.isNotEmpty(list)) {
                        String[] result = searchBug(url, list, testReport);
                        if(null != result && result.length > 0) {
                            return result;
                        }
                    }
                }
                return null;
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return null;
    }

    /**
     * 查询下一页的bug
     * 
     * @param url
     * @param list
     * @param testReport
     * 
     * @return
     * @throws Exception
     */
    private String[] searchBug(String url, List<Map<String, String>> list, TestReport testReport) throws Exception {

        for(Map<String, String> map : list) {
            String bugId = map.get("id");

            HttpResult httpResult = httpService.doGet(url + String.format(BUGDETAIL_URL, bugId), null);

            if (null == httpResult || httpResult.getCode().intValue() != 200) {
                logger.error("searchBug error.HttpStatusCode:{}", httpResult.getCode());
                continue;
            }

            JSONObject detailObject = JSONObject.parseObject(httpResult.getBody());
            Map<String, Object> detailMap = JSONObject.parseObject(detailObject.get("data").toString(), new TypeReference<Map<String, Object>> () {});
            Map<String, Object> bug = (Map<String, Object>)detailMap.get("bug");

            List<String> pathTitles = Lists.newArrayList();
            if(!Objects.isNull(bug.get("files"))) {
                Map<String, Object> files = (Map<String, Object>)bug.get("files");
                for(String key : files.keySet()) {
                    Map<String, String> file = (Map<String, String>)files.get(key);
                    pathTitles.add(file.get("title"));
                }
            }
            if(StringUtils.isEmpty(testReport.getLogFileIndex())
                    && StringUtils.isEmpty(testReport.getVideoFileIndex())) {
                if(CollectionUtils.isEmpty(pathTitles)) {
                    return new String[] {bugId, url + String.format(BUGDETAIL_HTML_URL, bugId)};
                }
            }else {
                int size = 0;
                if(StringUtils.isNotEmpty(testReport.getLogFileIndex())) {
                    size ++;
                }
                if(StringUtils.isNotEmpty(testReport.getVideoFileIndex())) {
                    size ++;
                }
                if(size == pathTitles.size()) {
                    if(StringUtils.isEmpty(testReport.getLogFileIndex())) {
                        if(pathTitles.stream().anyMatch(x -> StringUtils.equals(x, testReport.getVideoFileIndex()))) {
                            return new String[] {bugId, url + String.format(BUGDETAIL_HTML_URL, bugId)};
                        }
                    }else if(StringUtils.isEmpty(testReport.getVideoFileIndex())) {
                        if(pathTitles.stream().anyMatch(x -> StringUtils.equals(x, testReport.getLogFileIndex()))) {
                            return new String[] {bugId, url + String.format(BUGDETAIL_HTML_URL, bugId)};
                        }
                    }else {
                        if(pathTitles.stream().anyMatch(x -> StringUtils.equals(x, testReport.getVideoFileIndex()))
                                && pathTitles.stream().anyMatch(x -> StringUtils.equals(x, testReport.getLogFileIndex()))) {
                            return new String[] {bugId, url + String.format(BUGDETAIL_HTML_URL, bugId)};
                        }
                    }
                }
            }
        }
        return null;
    }

    @Override
    public Map<String, String> getPriorityList(ProjectProductionConfig projectProductionConfig) {
        // donoting
        return null;
    }

}
